
#include <iostream>
#include <cassert>
#include <stdlib.h>
#include <sys/shm.h>
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/videoio.hpp"

#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <assert.h>
#include <pthread.h>

#define key 65002
#define image_size_max 2400 * 3200

using namespace std;
using namespace cv;

typedef struct
{
    int rows;
    int cols;
    uchar dataPointer[image_size_max * 3];
    int mask_rows;
    int mask_cols;
    uchar maskPointer[image_size_max];
} image_head;

#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <semaphore.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>

int dump(int cam_num, int row_image, int col_image, void *block_data_image)
{
    static sem_t *semr = NULL, *semw = NULL, *semr2 = NULL, *semw2 = NULL;
    static image_head *buffer_head = nullptr;

    if (!buffer_head)
    {
        int shm_id = shmget(key, sizeof(image_head), 0666 | IPC_CREAT);
        if (shm_id == -1)
        {
            cout << "shmget error" << endl;
            return -1;
        }
        cout << " shem id is  " << shm_id << endl;

        buffer_head = (image_head *)shmat(shm_id, NULL, 0);

        if ((long)buffer_head == -1)
        {
            cout << "Share memary can't get pointer" << endl;
            return -1;
        }
        semr = sem_open("sem_r", O_CREAT | O_RDWR, 0666, 0);
        if (semr == SEM_FAILED)
        {
            printf("errno = %d\n", errno);
            return -1;
        }

        semw = sem_open("sem_w", O_CREAT | O_RDWR, 0666, 0);
        if (semw == SEM_FAILED)
        {
            printf("errno = %d\n", errno);
            return -1;
        }
        semr2 = sem_open("sem_r2", O_CREAT | O_RDWR, 0666, 0);
        if (semr == SEM_FAILED)
        {
            printf("errno = %d\n", errno);
            return -1;
        }

        semw2 = sem_open("sem_w2", O_CREAT | O_RDWR, 0666, 0);
        if (semw == SEM_FAILED)
        {
            printf("errno = %d\n", errno);
            return -1;
        }
        // sem_post(semw);
        // sem_post(semw2);
    }
    if (cam_num == 0)
    {
        // std::cout << "w rgb" << std::endl;
        sem_wait(semw);
        buffer_head->rows = row_image;
        buffer_head->cols = col_image;
        memcpy(buffer_head->dataPointer, block_data_image, row_image * col_image * 3);
    }
    else
    {
        // std::cout << "w mask" << std::endl;
        // buffer_head->mask_rows = row_image;
        // buffer_head->mask_cols = col_image;
        sem_wait(semw2);
        // printf("%x\n", buffer_head->maskPointer);
        // printf("%x\n", buffer_head->dataPointer);
        buffer_head->mask_rows = row_image;
        buffer_head->mask_cols = col_image;
        memcpy(buffer_head->maskPointer, block_data_image, row_image * col_image);
    }

    if (cam_num == 0)
    {
        // std::cout << "w rgb" << std::endl;
        sem_post(semr);
    }
    else
    {
        // std::cout << "w mask" << std::endl;
        sem_post(semr2);
    }

    // sem_post(semr);
    // std::cout << "semr" << std::endl;

    // 解锁
    // pthread_mutex_unlock(&(mp->lock));

    return 1;
}

uchar *read(int cam_num)
{
    static sem_t *semr = NULL, *semw = NULL, *semr2 = NULL, *semw2 = NULL;
    static image_head *buffer_head = nullptr;

    if (!buffer_head)
    {
        int shm_id = shmget(key, sizeof(image_head), 0666 | IPC_CREAT);
        if (shm_id == -1)
        {
            cout << "shmget error" << endl;
            return 0;
        }
        cout << " shem id is  " << shm_id << endl;

        buffer_head = (image_head *)shmat(shm_id, NULL, 0);

        if ((long)buffer_head == -1)
        {
            cout << "Share memary can't get pointer" << endl;
            return 0;
        }

        semr = sem_open("sem_r", O_CREAT | O_RDWR, 0666, 1);
        if (semr == SEM_FAILED)
        {
            printf("errno = %d\n", errno);
            return 0;
        }

        semw = sem_open("sem_w", O_CREAT | O_RDWR, 0666, 1);
        if (semw == SEM_FAILED)
        {
            printf("errno = %d\n", errno);
            return 0;
        }
        semr2 = sem_open("sem_r2", O_CREAT | O_RDWR, 0666, 0);
        if (semr == SEM_FAILED)
        {
            printf("errno = %d\n", errno);
            return 0;
        }

        semw2 = sem_open("sem_w2", O_CREAT | O_RDWR, 0666, 0);
        if (semw == SEM_FAILED)
        {
            printf("errno = %d\n", errno);
            return 0;
        }
        // sem_post(semw2);
        sem_post(semw);
        // sem_wait(semw);
        // std::cout << "r init" << std::endl;
    }

    if (cam_num == 0)
    {
        // std::cout << "r rgb" << std::endl;

        sem_wait(semr);
        sem_post(semw2);
    }
    else
    {
        // std::cout << "r mask" << std::endl;
        sem_wait(semr2);
        sem_post(semw);
    }

    if (cam_num == 1) // mask
        return (uchar *)&(buffer_head->mask_rows);
    else
        return (uchar *)buffer_head;
}

extern "C"
{
    int dump_(int cam_num, int row_image, int col_image, void *block_data_image)
    {
        int result = dump(cam_num, row_image, col_image, block_data_image);
        return result;
    }
    uchar *read_(int cam_num)
    {
        uchar *result = read(cam_num);
        return result;
    }
}
